package cn.matezk.lianlian.task;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.matezk.lianlian.dao.DeviceDao;
import cn.matezk.lianlian.dao.UserDeviceDao;
import cn.matezk.lianlian.model.Device;
import cn.matezk.lianlian.model.UserDevice;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.iotexplorer.v20190423.IotexplorerClient;
import com.tencentcloudapi.iotexplorer.v20190423.models.*;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class DeviceSyncTask {
    @Value("${tencent.endpoint}")
    private String endpoint;
    @Value("${tencent.region}")
    private String region;
    @Value("${tencent.secret-id}")
    private String secretId;
    @Value("${tencent.secret-key}")
    private String secretKey;

    private Map<String, String> pMap = new HashMap<>();

    @Autowired
    private WxMaService wxMaService;
    @Autowired
    private DeviceDao deviceDao;
    @Autowired
    private UserDeviceDao userDeviceDao;

    @XxlJob("deviceSyncTask")
    public void execute() throws TencentCloudSDKException, InterruptedException {
        List<String> ps = productList();
        for (String p : ps) {
            XxlJobHelper.log(String.format("同步产品: %s", p));
            List<DeviceInfo> devs = productDevice(p);
            if (ObjectUtil.isEmpty(devs))   continue;
            // 获取设备ID集合
            List<String> ids = new ArrayList<>();
            for (DeviceInfo info : devs) {
                ids.add(info.getProductId().concat("/").concat(info.getDeviceName()));
            }
            // 查询数据库已经存在的
            List<Device> dbs = deviceDao.selectByProductId(p);
            if (ObjectUtil.isNotEmpty(dbs)) {
                for (Device dev : dbs) {
                    if (!ids.contains(dev.getDeviceId())) {
                        // 删除不存在的
                        deviceDao.deleteByPrimaryKey(dev.getDeviceId());
                        userDeviceDao.unbindByDeviceId(dev.getDeviceId());
                    }
                }
            }
            for (DeviceInfo info : devs) {
                String deviceId = info.getProductId().concat("/").concat(info.getDeviceName());
                XxlJobHelper.log(String.format("同步设备: %s", deviceId));
                // 删除绑定关系
                userDeviceDao.unbindByDeviceId(deviceId);
                DeviceUser[] us = deviceUserList(info.getProductId(), info.getDeviceName());
                XxlJobHelper.log(JSONUtil.toJsonStr(us));
                Device dv = deviceDao.selectByPrimaryKey(deviceId);
                if (ObjectUtil.isNull(dv)) {
                    dv = new Device();
                    dv.setDeviceId(deviceId);
                    dv.setProductId(info.getProductId());
                    dv.setDeviceName(info.getDeviceName());
                    if (ObjectUtil.isNotEmpty(us)) {
                        dv.setFamilyId(us[0].getFamilyId());
                    }
                    dv.setAliasName(pMap.get(info.getProductId()));
                    deviceDao.insertSelective(dv);
                } else {
                    Device ud = new Device();
                    ud.setDeviceId(deviceId);
                    if (ObjectUtil.isNotEmpty(us)) {
                        ud.setFamilyId(us[0].getFamilyId());
                    }
                    if (ObjectUtil.isEmpty(dv.getAliasName())) {
                        ud.setAliasName(pMap.get(info.getProductId()));
                    }
                    if (ObjectUtil.isNull(dv.getExFactoryTime()) && ObjectUtil.isNull(dv.getPrintTime())) {
                        ud.setExFactoryTime(new Date(info.getCreateTime()));
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTime(ud.getExFactoryTime());
                        calendar.set(Calendar.DAY_OF_MONTH, 1);
                        calendar.add(Calendar.DATE, -1);
                        calendar.add(Calendar.MONTH, 2);
                        ud.setFlowPkg(1);
                        ud.setExpireDate(calendar.getTime());
                    }
                    if (ObjectUtil.isNotEmpty(ud.getFamilyId()) || ObjectUtil.isNotEmpty(ud.getAliasName())) {
                        deviceDao.updateByPrimaryKeySelective(ud);
                    }
                }
                if (ObjectUtil.isNotEmpty(us)) {
                    List<UserDevice> uds = new ArrayList<>();
                    for (DeviceUser du : us) {
                        UserDevice ud = new UserDevice();
                        ud.setDeviceId(deviceId);
                        ud.setUserId(du.getUserId());
                        ud.setRole(du.getRole().intValue());
                        uds.add(ud);
                    }
                    userDeviceDao.batchBind(uds);
                }
            }
        }
        XxlJobHelper.log("同步完成");
    }

    private DeviceUser[] deviceUserList(String productId, String deviceName) {
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint(endpoint);
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        Credential credential = new Credential(secretId, secretKey);
        IotexplorerClient client = new IotexplorerClient(credential, region, clientProfile);
        GetFamilyDeviceUserListRequest request = new GetFamilyDeviceUserListRequest();
        request.setProductId(productId);
        request.setDeviceName(deviceName);
        try {
            GetFamilyDeviceUserListResponse response = client.GetFamilyDeviceUserList(request);
            return response.getUserList();
        }catch (TencentCloudSDKException e) {
            return null;
        }
    }

    private List<DeviceInfo> productDevice(String productId) throws TencentCloudSDKException {
        List<DeviceInfo> devs = new ArrayList<>();
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint(endpoint);
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        Credential credential = new Credential(secretId, secretKey);
        IotexplorerClient client = new IotexplorerClient(credential, region, clientProfile);
        GetDeviceListRequest request = new GetDeviceListRequest();
        request.setProductId(productId);
        long offset = 0L;
        while (true) {
            request.setOffset(offset);
            request.setLimit(100L);
            GetDeviceListResponse response = client.GetDeviceList(request);
            if (ObjectUtil.isNotEmpty(response.getDevices())) {
                devs.addAll(Arrays.asList(response.getDevices()));
                offset += response.getDevices().length;
            }
            if (ObjectUtil.isEmpty(response.getDevices()) || response.getDevices().length < 100) {
                break;
            }
        }
        return devs;
    }

    private List<String> productList() throws TencentCloudSDKException {
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint(endpoint);
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        Credential credential = new Credential(secretId, secretKey);
        GetStudioProductListRequest request = new GetStudioProductListRequest();

        IotexplorerClient client = new IotexplorerClient(credential, region, clientProfile);
        GetStudioProductListResponse response = client.GetStudioProductList(request);
        ProductEntry[] products = response.getProducts();
        List<String> ps = new ArrayList<>();
        for (ProductEntry p : products) {
            ps.add(p.getProductId());
            pMap.put(p.getProductId(), p.getProductName());
        }
        return ps;
    }
}
